background gl
https://gyazo.com/d3cd73904ee8993d019ee478b2462b26
概要
右メニューのボタンからテンプレートの名前をクリックすることでテーマを変更できる
frag.gl, vert.glがあるページではそれが読み込まれ、表示される
一度正しく読み込まれたテーマは次にロードするまで右のメニューから再度表示可能
外部訪問者に見せることはできない
詳細
ユーザーのページにインポートする前の設定を書き込むことで最初に読み込まれた時のテーマを決めることができる
window.glsl_frag window.glsl_vert
テンプレートからデフォルトを選択
or
URL を指定
window.glsl_vertは未設定でも化
code:settings.js
window.glsl_frag = "beam"
// window.glsl_frag = "/api/code/{projectname}/{pagename}/frag.gl"
// window.glsl_vert = "/api/code/{projectname}/{pagename}/vert.gl"
code:_script.js
import "/api/code/{projectname}/{username}/settings.js"
import "/api/code/yutaro/background-gl/script.js"
そのままではなぜか動かないので変数名などを置き換え
次のようにそれぞれ置き換えると動く(理由は分かっていない)
time => u_time
mouse => u_mouse
resolution => u_resolution
余談
glslを勉強し始めたので、scrapboxに飾るために作った!
ユーザーごとのsettings.jsは試験的に便利かどうか検討中
window.____で設定を記述できる
設定の方を確実に先に読み込ませるために別ファイルにしてimport
glslは完全に初心者で色々よくわかっていないのでバグが結構あるかも...
こんな感じでカードを透過させるとメニュー画面がかっこよくなるのでオススメ
code:style.css
.grid li.page-list-item a .header {
border-top: rgba(100,255,100, 0.2) solid 3px;
}
.grid li.page-list-item a {
background-color: rgba(0,0,0,0);
}
code:script.js
import GlslCanvas from '/api/code/spm/GlslCanvas/script.js'
if( window.glsl_frag === undefined ) {
window.glsl_frag = 'none'
}
const canvas = document.createElement('canvas')
canvas.width = window.parent.screen.width
canvas.height = window.parent.screen.height
canvas.style = position:fixed; z-index: -1; top: 0; left: 0;
$('#app-container').append(canvas)
let sandbox = new GlslCanvas(canvas)
function load(frag, vert = undefined ) {
if ( frag === "none" ) return
if ( !frag.includes('/') ) {
frag = /api/code/yutaro/background_gl/${frag}.gl
}
return ( async () => {
const fs = await fetch( frag ,
{ credentials: 'same-origin'})
.then( data => data.text())
.catch( err => err )
if( fs.length === 0 ) return false;
if( !vert ) {
sandbox.load(fs)
return false;
}
const vs = await fetch( vert ,
{ credentials: 'same-origin'})
.then( data => data.text())
.catch( err => err )
if( vs.length === 0 ) sandbox.load(fs)
else sandbox.load(fs, vs)
return true;
})()
}
load(window.glsl_frag, window.glsl_vert);
scrapbox.PageMenu.addMenu({
title: 'glsl',
})
frags.forEach( frag => {
scrapbox.PageMenu('glsl').addItem({
title: frag,
onClick: () => load(frag)
})
})
let url = "/"
let items = []
setInterval( () => {
const path = location.pathname
// ここの例外処理をちゃんと書く
if ( url === path
|| /^\/\w-+\/$/.test(path) || path.includes('settings')
|| path.includes('stream') ) return
url = path
load(/api/code${path}/frag.gl,/api/code${path}/vert.gl)
.then( flag => {
if( !flag ) return;
const pageName = path.split('/')2 if(items.includes( pageName )) return;
items.push(pageName)
scrapbox.PageMenu('glsl').addItem({
title: pageName,
onClick: () => load(/api/code${path}/frag.gl,/api/code${path}/vert.gl)
})
});
}, 10)
code:gradation.gl
// Author:
// Title:
precision mediump float;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
vec3 color = vec3(0.);
color = vec3(st.x,st.y,abs(sin(u_time)));
gl_FragColor = vec4(color,1.0);
}
code:beam.gl
precision mediump float;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
float DEG2RAG = .0174532925199;
float tri2(vec2 pos)
{
float a = dot(pos, vec2(sin( 60.0*DEG2RAG), cos( 60.0*DEG2RAG)));
float b = dot(pos, vec2(sin(-60.0*DEG2RAG), cos(-60.0*DEG2RAG)));
float c = -pos.y;
float d = 0.2*cos(60.0*DEG2RAG);
float u1 = a - d*0.25;
float v1 = b - d*0.25;
float w1 = c - d*0.25;
float u2 = c + d*1.25;
float v2 = b + d*1.25;
float w2 = a + d*1.25;
float t1 = min(u2, min(u1, v1));
float t2 = min(v2, min(w1, u1));
float t3 = min(w2, min(v1, w1));
float res = max(max(t1, t2), t3);
return 0.002/abs(res);
}
float tri(vec2 pos)
{
float a = dot(pos, vec2(sin( 60.0*DEG2RAG), cos( 60.0*DEG2RAG)));
float b = dot(pos, vec2(sin(-60.0*DEG2RAG), cos(-60.0*DEG2RAG)));
float c = -pos.y;
float result = 0.002/abs(min(min(0.05-a,0.05-b), 0.05-c));
return result;
}
void main() {
vec2 pos = (2.0*gl_FragCoord.xy - u_resolution.xy)/max(u_resolution.x, u_resolution.y) / 16.0;
//rotate & zoom
mat2 rot = mat2(cos(u_time),-sin(u_time),
sin(u_time), cos(u_time));
pos *= rot;
float zoom = 1.0/(mod(u_time, 1.0)+1.0)*3.0-1.0;
pos *= zoom;
//effect
vec3 result = vec3(0.0);
for(int i = 0 ; i < 6 ; i++)
{
result += vec3(tri(pos), tri(-pos*0.5), tri2(pos));
pos /= 0.25;
}
gl_FragColor = vec4( mix(vec3(0.0, 0.0, 0.0), vec3(0.5, 0.0,1.0), result.x)
+mix(vec3(0.0, 0.0, 0.0), vec3(0.5,0.25,0.0), result.y)
+mix(vec3(0.0, 0.0, 0.0), vec3(0.0,0.5,0.1), result.z), 1.0 );
}
code:blocks.gl
// @lsdlive
// This was my shader for the shader showdown at Outline demoparty 2018 in Nederland.
// Shader showdown is a live-coding competition where two participants are
// facing each other during 25 minutes.
// (Round 1)
// I don't have access to the code I typed at the event, so it might be
// slightly different.
// Thanks to shadertoy community & shader showdown paris.
// This is under CC-BY-NC-SA (shadertoy default licence)
precision mediump float;
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
mat2 r2d(float a) {
float c = cos(a), s = sin(a);
return mat2(c, s, -s, c);
}
vec2 path(float t) {
float a = sin(t*.2 + 1.5), b = sin(t*.2);
return vec2(2.*a, a*b);
}
float g = 0.;
float de(vec3 p) {
p.xy -= path(p.z);
float d = -length(p.xy) + 4.;// tunnel (inverted cylinder)
p.xy += vec2(cos(p.z + iTime)*sin(iTime), cos(p.z + iTime));
p.z -= 6. + iTime * 6.;
d = min(d, dot(p, normalize(sign(p))) - 1.); // octahedron (LJ's formula)
// I added this in the last 1-2 minutes, but I'm not sure if I like it actually!
// Trick inspired by balkhan's shadertoys.
// Usually, in raymarch shaders it gives a glow effect,
// here, it gives a colors patchwork & transparent voxels effects.
g += .015 / (.001 + d * d);
return d;
}
void main()
{
vec2 uv = gl_FragCoord.xy / u_resolution.xy - .5;
uv.x *= u_resolution.x / u_resolution.y;
float dt = u_time * 6.;
vec3 ro = vec3(0, 0, -5. + dt);
vec3 ta = vec3(0, 0, dt);
ro.xy += path(ro.z);
ta.xy += path(ta.z);
vec3 fwd = normalize(ta - ro);
vec3 right = cross(fwd, vec3(0, 1, 0));
vec3 up = cross(right, fwd);
vec3 rd = normalize(fwd + uv.x*right + uv.y*up);
rd.xy *= r2d(sin(-ro.x / 3.14)*.3);
// Raycast in 3d to get voxels.
// Algorithm fully explained here in 2D (just look at dde algo):
// Basically, tracing a ray in a 3d grid space, and looking for
// each voxel (think pixel with a third dimension) traversed by the ray.
vec3 p = floor(ro) + .5;
vec3 mask;
vec3 drd = 1. / abs(rd);
rd = sign(rd);
vec3 side = drd * (rd * (p - ro) + .5);
float t = 0., ri = 0.;
for (float i = 0.; i < 1.; i += .01) {
ri = i;
/*
// sphere tracing algorithm (for comparison)
p = ro + rd * t;
float d = de(p);
if(d<.001) break;
t += d;
*/
if (de(p) < 0.) break;// distance field
// we test if we are inside the surface
mask = step(side, side.yzx) * step(side, side.zxy);
// minimum value between x,y,z, output 0 or 1
side += drd * mask;
p += rd * mask;
}
t = length(p - ro);
vec3 c = vec3(1) * length(mask * vec3(1., .5, .75));
c = mix(vec3(.2, .2, .7), vec3(.2, .1, .2), c);
c += g * .4;
c.r += sin(u_time)*.2 + sin(p.z*.5 - u_time * 6.);// red rings
c = mix(c, vec3(.2, .1, .2), 1. - exp(-.001*t*t));// f
gl_FragColor = vec4(c, 1.0);
}
code:smog.gl
precision highp float;
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
float triangle(float x, float a)
{
float output2 = 2.0*abs( 2.0* ( (x/a) - floor( (x/a) + 0.5) ) ) - 1.0;
return output2;
}
float field(in vec3 p)
{
float strength = 7.0 + 0.03 * log(1.e-6 + fract(sin(u_time) * 4373.11));
float accum = 0.0;
float prev = 0.0;
float tw = 0.0;
for (int i = 0; i < 4; ++i)
{
float mag = dot(p, p);
p = abs(p) / mag + vec3(-.5, -.8 + 0.1*sin(u_time*0.2 + 2.0), -1.1+0.3*cos(u_time*0.15));
float w = exp(-float(i) / 7.);
accum += w * exp(-strength * pow(abs(mag - prev), 2.3));
tw += w;
prev = mag;
}
return max(0., 5. * accum / tw - .7);
}
void main()
{
vec2 uv2 = 2. * gl_FragCoord.xy / u_resolution.xy - 1.;
vec2 uvs = uv2 * u_resolution.xy / max(u_resolution.x, u_resolution.y);
float time2 = u_time*1.9;
float speed = speed2;
speed = 0.005 * cos(time2*0.02 + 3.1415926/4.0);
//speed = 0.0;
float formuparam = formuparam2;
//get coords and direction
vec2 uv = uvs;
//mouse rotation
float a_xz = 0.9;
float a_yz = -.6;
float a_xy = 0.9 + u_time*0.04;
mat2 rot_xz = mat2(cos(a_xz),sin(a_xz),-sin(a_xz),cos(a_xz));
mat2 rot_yz = mat2(cos(a_yz),sin(a_yz),-sin(a_yz),cos(a_yz));
mat2 rot_xy = mat2(cos(a_xy),sin(a_xy),-sin(a_xy),cos(a_xy));
float v2 =1.0;
vec3 dir=vec3(uv*zoom,1.);
vec3 from=vec3(0.0, 0.0,0.0);
from.x -= .5*(-0.5);
from.y -= .5*(-0.5);
vec3 forward = vec3(0.,0.,1.);
from.x += transverseSpeed*(1.0)*cos(0.01*u_time) + 0.001*u_time;
from.y += transverseSpeed*(1.0)*sin(0.01*u_time) + 0.001*u_time;
from.z += 0.003*u_time;
dir.xy*=rot_xy;
forward.xy *= rot_xy;
dir.xz*=rot_xz;
forward.xz *= rot_xz;
dir.yz*= rot_yz;
forward.yz *= rot_yz;
from.xy*=-rot_xy;
from.xz*=rot_xz;
from.yz*= rot_yz;
//zoom
float zooom = (time2-3311.)*speed;
from += forward* zooom;
float sampleShift = mod( zooom, stepsize );
float zoffset = -sampleShift;
sampleShift /= stepsize; // make from 0 to 1
//volumetric rendering
float s=0.24;
float s3 = s + stepsize/2.0;
vec3 v=vec3(0.);
float t3 = 0.0;
vec3 backCol2 = vec3(0.);
for (int r=0; r<volsteps; r++) {
vec3 p2=from+(s+zoffset)*dir;// + vec3(0.,0.,zoffset);
vec3 p3=(from+(s3+zoffset)*dir )* (1.9/zoom);// + vec3(0.,0.,zoffset);
p2 = abs(vec3(tile)-mod(p2,vec3(tile*2.))); // tiling fold
p3 = abs(vec3(tile)-mod(p3,vec3(tile*2.))); // tiling fold
t3 = field(p3);
float pa,a=pa=0.;
for (int i=0; i<iterations; i++) {
p2=abs(p2)/dot(p2,p2)-formuparam; // the magic formula
//p=abs(p)/max(dot(p,p),0.005)-formuparam; // another interesting way to reduce noise
float D = abs(length(p2)-pa); // absolute sum of average change
if (i > 2)
{
a += i > 7 ? min( 12., D) : D;
}
pa=length(p2);
}
//float dm=max(0.,darkmatter-a*a*.001); //dark matter
a*=a*a; // add contrast
//if (r>3) fade*=1.-dm; // dark matter, don't render near
// brightens stuff up a bit
float s1 = s+zoffset;
// need closed form expression for this, now that we shift samples
float fade = pow(distfading,max(0.,float(r)-sampleShift));
//t3 += fade;
v+=fade;
//backCol2 -= fade;
// fade out samples as they approach the camera
if( r == 0 )
fade *= (1. - (sampleShift));
// fade in samples as they approach from the distance
if( r == volsteps-1 )
fade *= sampleShift;
v+=vec3(s1,s1*s1,s1*s1*s1*s1)*a*brightness*fade; // coloring based on distance
backCol2 += mix(.4, 1., v2) * vec3(0.20 * t3 * t3 * t3, 0.4 * t3 * t3, t3 * 0.7) * fade;
s+=stepsize;
s3 += stepsize;
}
v=mix(vec3(length(v)),v,saturation); //color adjust
vec4 forCol2 = vec4(v*.01,1.);
backCol2 *= cloud;
backCol2.r *= 1.80;
backCol2.g *= 0.05;
backCol2.b *= 0.90;
// backCol2.b = 0.5*mix(backCol2.b, backCol2.g, 0.2);
// backCol2.g = 0.0;
//
// backCol2.bg = mix(backCol2.gb, backCol2.bg, 0.5*(cos(u_time*0.01) + 1.0));
gl_FragColor = vec4(backCol2, 1.0);
}
code:fusion.gl
precision mediump float;
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
void main( void ) {
float dist= 2.7;
vec2 p = gl_FragCoord.xy / u_resolution.xy * 2. - 1.;
p.x *= u_resolution.x/u_resolution.y;
p*=1.5;
p=(p);
float a = sin(atan(p.y,p.x))*cos(atan(p.y,p.x))*2.;
float l = log(length(p))*1.5;
float c = sin((l+cos(a*1.-sin(a*2.-u_time*5.)+u_time*3.2)+a*2.+u_time*0.5));
c*=log(abs(l*dist))/1.5;
//c*=sin(l*dist);
gl_FragColor = vec4((c),c*c,-c,1.0 );
}
code:mono.gl
precision mediump float;
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
vec2 brickTile(vec2 uv, float zoom)
{
uv *= zoom;
uv.x += step(1., mod(uv.y,2.0)) * -u_time;
return fract(uv);
}
vec2 brickTile2(vec2 uv, float zoom)
{
uv *= zoom;
float t = mod(uv.y,2.0) < 1. ? -u_time : u_time;
uv.x += step(0., mod(uv.y,2.0)) * t;
return fract(uv);
}
vec2 brickTile3(vec2 uv, float zoom)
{
uv *= zoom;
float tx = mod(uv.y,2.0) < 1. ? -u_time : u_time;
float ty = mod(uv.x,2.0) < 1. ? -u_time : u_time;
float b = step(1.,mod(u_time,2.));
if(b < 1.)
{
uv.x += step(0., mod(uv.y,2.0)) * tx;
}
else
{
uv.y += step(0., mod(uv.x,2.0)) * ty;
}
return fract(uv);
}
void main( void ) {
vec2 position = ( gl_FragCoord.xy / u_resolution.xy );
position.x *= u_resolution.x / u_resolution.y;
//position = brickTile(position,5.);
//position = brickTile2(position,10.);
position = brickTile3(position,10.);
float d = distance(position,vec2(.5));
float radius = 0.2;
float s = smoothstep(radius,d + radius, d);
vec3 color = vec3(s * 5.);
color = mix(color,1.- color,sin(u_time) + 1.);
gl_FragColor = vec4( color , 1.0 );
}
code:marin.gl
/*
Iridule ~
shadertoy: iridule
twitter: @iridule
instagram: @the_iridule
email: numinouscranium@gmail.com
*/
precision mediump float;
uniform float u_time;
uniform vec2 u_resolution;
vec2 iResolution;
float iTime;
#define repeat(v) mod(p + 1., 2.) -1. mat3 rotateX(float a) {
return mat3(
1.0, 0.0, 0.0,
0.0, cos(a), sin(a),
0.0, -sin(a), cos(a)
);
}
mat3 rotateY(float a) {
return mat3(
cos(a), 0.0, sin(a),
0.0, 1.0, 0.0,
-sin(a), 0.0, cos(a)
);
}
float sphere_sdf(vec3 p, float r) {
return length(p) - r;
}
float cube_sdf(vec3 p, float s) {
return length(max(abs(p) - s, .0));
}
float ring_sdf(vec3 p) {
float a = sphere_sdf(p + vec3(.2, .0, .0), .1);
float b = sphere_sdf(p + vec3(-.2, .0, .0), .1);
float A = un(a, b);
float c = sphere_sdf(p + vec3(.0, .0, .1), .1);
float d = sphere_sdf(p + vec3(.0, .0, -.1), .1);
float B = un(c, d);
return un(A, B);
}
float shape_sdf(vec3 p) {
vec3 v = rotateY(iTime) * p;
v.y = mod(v.y + 0.2, 0.4) - 0.2;
return un(ring_sdf(v),
sphere_sdf(p * vec3(1., .01, 1.), .11));
}
void mainImage(out vec4 O, in vec2 I) {
vec2 R = iResolution.xy;
vec2 uv = (2. * I - R) / R.y;
vec3 o = vec3(-1., 0., iTime), d = vec3(uv, 1.), p;
float t = 0.;
for (int i = 0; i < 32; i++) {
p = o + d * t;
p = repeat(p);
t += .5 * shape_sdf(p);
}
float l = .8 * dot(normalize(o - p), d);
O = vec4(.5 * vec3(0., uv.y, uv.y) + vec3(.0, .3, 1.) * l * vec3(t * .3), 1.);
}
void main(void) {
iResolution = u_resolution;
iTime = u_time;
mainImage(gl_FragColor, gl_FragCoord.xy);
}
code:neon.gl
precision mediump float;
uniform float u_time;
uniform vec2 u_resolution;
void main( void ) {
vec2 p = ( gl_FragCoord.xy / u_resolution.x );
float scale = 65.0*(1.5+cos(u_time/13.0 + sin(p.x)+ sin(p.y)));
vec3 hue = vec3(p.x,p.y,0.0);
float color = 0.0;
color = (sin(p.x*scale) + sin(p.y*scale) -1.7)*4.0;
gl_FragColor = vec4( color * hue, 1.0 );
}
code:sea.gl
precision mediump float;
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
// "Seascape" by Alexander Alekseev aka TDM - 2014
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
const int NUM_STEPS = 16;
const float PI = 3.1415;
const float EPSILON = 1e-3;
float EPSILON_NRM = 0.;
// sea
const int ITER_GEOMETRY = 3;
const int ITER_FRAGMENT = 5;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 4.0;
const float SEA_SPEED = 0.8;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.2,0.19,0.22);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
float SEA_TIME = 0.;
mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
// math
mat3 fromEuler(vec3 ang) {
vec2 a1 = vec2(sin(ang.x),cos(ang.x));
vec2 a2 = vec2(sin(ang.y),cos(ang.y));
vec2 a3 = vec2(sin(ang.z),cos(ang.z));
mat3 m;
m0 = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x); m1 = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x); m2 = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y); return m;
}
float hash( vec2 p ) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
vec2 i = floor( p );
vec2 f = fract( p );
vec2 u = f*f*(3.0-2.0*f);
return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),
hash( i + vec2(1.0,0.0) ), u.x),
mix( hash( i + vec2(0.0,1.0) ),
hash( i + vec2(1.0,1.0) ), u.x), u.y);
}
// lighting
float diffuse(vec3 n,vec3 l,float p) {
return pow(dot(n,l) * 0.1 + 0.6,p);
}
float specular(vec3 n,vec3 l,vec3 e,float s) {
float nrm = (s + 8.0) / (3.1415 * 8.0);
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
// sky
vec3 getSkyColor(vec3 e) {
e.y = max(e.y,0.0);
vec3 ret;
ret.x = pow(1.0-e.y,2.0);
ret.y = 1.0-e.y;
ret.z = 0.6+(1.0-e.y)*0.4;
return ret;
}
// sea
float sea_octave(vec2 uv, float choppy) {
uv += noise(uv);
vec2 wv = 1.0-abs(sin(uv));
vec2 swv = abs(cos(uv));
wv = mix(wv,swv,wv);
return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}
float map(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_GEOMETRY; i++) {
d = sea_octave((uv+SEA_TIME)*freq,choppy);
d += sea_octave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
float map_detailed(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_FRAGMENT; i++) {
d = sea_octave((uv+SEA_TIME)*freq,choppy);
d += sea_octave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
float fresnel = 1.0 - max(dot(n,-eye),0.0);
fresnel = pow(fresnel,3.0) * 0.65;
vec3 reflected = getSkyColor(reflect(eye,n));
vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
vec3 color = mix(refracted,reflected,fresnel);
float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
color += vec3(specular(n,l,eye,60.0));
return color;
}
// tracing
vec3 getNormal(vec3 p, float eps) {
vec3 n;
n.y = map_detailed(p);
n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
n.y = eps;
return normalize(n);
}
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
float tm = 0.0;
float tx = 1000.0;
float hx = map(ori + dir * tx);
if(hx > 0.0) return tx;
float hm = map(ori + dir * tm);
float tmid = 0.0;
for(int i = 0; i < NUM_STEPS; i++) {
tmid = mix(tm,tx, hm/(hm-hx));
p = ori + dir * tmid;
float hmid = map(p);
if(hmid < 0.0) {
tx = tmid;
hx = hmid;
} else {
tm = tmid;
hm = hmid;
}
}
return tmid;
}
// main
void main( void ) {
EPSILON_NRM = 0.1 / u_resolution.x;
SEA_TIME = u_time * SEA_SPEED;
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
uv = uv * 2.0 - 1.0;
uv.x *= u_resolution.x / u_resolution.y;
float u_time = u_time * 0.3 + u_mouse.x*0.01;
// ray
vec3 ang = vec3(sin(u_time*3.0)*0.1,sin(u_time)*0.2+0.3,u_time);
vec3 ori = vec3(0.0,3.5,u_time*5.0);
vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;
dir = normalize(dir) * fromEuler(ang);
// tracing
vec3 p;
heightMapTracing(ori,dir,p);
vec3 dist = p - ori;
vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
vec3 light = normalize(vec3(0.0,1.0,0.8));
// color
vec3 color = mix(
getSkyColor(dir),
getSeaColor(p,n,light,dir,dist),
pow(smoothstep(0.0,-0.05,dir.y),0.3));
// post
gl_FragColor = vec4(pow(color,vec3(0.75)), 1.0);
}